using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;

namespace AntEater.ComponentModel
{
    /// <summary>
    /// Represents a collection of external build properties
    /// </summary>
    [Serializable]
    public class ExternalBuildPropertyCollection : Collection<ExternalBuildProperty>
    {
        /// <summary>
        /// Occurs when the instance or some of his child objects has changed.
        /// </summary>
        public event EventHandler<EventArgs> Changed;

        /// <summary>
        /// Occurs when the collection changed.
        /// </summary>
        public event EventHandler<CollectionChangeEventArgs> CollectionChanged;

        /// <summary>
        /// Gets the <see cref="AntEater.ComponentModel.ExternalBuildProperty"/> with the specified name.
        /// </summary>
        /// <value></value>
        public ExternalBuildProperty this[string name] {
            get {

                if (name == null) { throw new ArgumentNullException("name"); }

                ExternalBuildProperty result = null;

                foreach (ExternalBuildProperty property in this) {
                    if (property.Name == name) {
                        result = property;
                    }
                }

                return result;
            }
        }

        /// <summary>
        /// Adds a collection of external build properties to the colecttion.
        /// </summary>
        /// <param name="collection">The collection.</param>
        public void AddRange(IEnumerable<ExternalBuildProperty> collection) {
            
            if (collection == null) { throw new ArgumentNullException("collection"); }

            foreach (ExternalBuildProperty property in collection) {
                this.Add(property);
            }
        }

        /// <summary>
        /// Returns an array.
        /// </summary>
        /// <returns>An array of external build properties.</returns>
        public ExternalBuildProperty[] ToArray() {
            ExternalBuildProperty[] result = new ExternalBuildProperty[this.Count];
            this.CopyTo(result, 0);

            return result;
        }

        /// <summary>
        /// Inserts an element into the <see cref="T:System.Collections.ObjectModel.Collection`1"></see> at the specified index.
        /// </summary>
        /// <param name="index">The zero-based index at which item should be inserted.</param>
        /// <param name="item">The object to insert. The value can be null for reference types.</param>
        /// <exception cref="T:System.ArgumentOutOfRangeException">index is less than zero.-or-index is greater than <see cref="P:System.Collections.ObjectModel.Collection`1.Count"></see>.</exception>
        protected override void InsertItem(int index, ExternalBuildProperty item) {

            base.InsertItem(index, item);
            item.Changed += new EventHandler<EventArgs>(ItemChanged);

            this.OnCollectionChanged(CollectionChangeAction.Add);
        }

        /// <summary>
        /// Replaces the element at the specified index.
        /// </summary>
        /// <param name="index">The zero-based index of the element to replace.</param>
        /// <param name="item">The new value for the element at the specified index. The value can be null for reference types.</param>
        /// <exception cref="T:System.ArgumentOutOfRangeException">index is less than zero.-or-index is greater than <see cref="P:System.Collections.ObjectModel.Collection`1.Count"></see>.</exception>
        protected override void SetItem(int index, ExternalBuildProperty item) {

            this[index].Changed -= new EventHandler<EventArgs>(ItemChanged);
            base.SetItem(index, item);
            item.Changed += new EventHandler<EventArgs>(ItemChanged);

            this.OnCollectionChanged(CollectionChangeAction.Refresh);
        }

        /// <summary>
        /// Removes the element at the specified index of the <see cref="T:System.Collections.ObjectModel.Collection`1"></see>.
        /// </summary>
        /// <param name="index">The zero-based index of the element to remove.</param>
        /// <exception cref="T:System.ArgumentOutOfRangeException">index is less than zero.-or-index is equal to or greater than <see cref="P:System.Collections.ObjectModel.Collection`1.Count"></see>.</exception>
        protected override void RemoveItem(int index) {

            this[index].Changed -= new EventHandler<EventArgs>(ItemChanged);
            base.RemoveItem(index);

            this.OnCollectionChanged(CollectionChangeAction.Remove);
        }

        /// <summary>
        /// Removes all elements from the <see cref="T:System.Collections.ObjectModel.Collection`1"></see>.
        /// </summary>
        protected override void ClearItems() {

            foreach (ExternalBuildProperty item in this) {
                item.Changed -= new EventHandler<EventArgs>(ItemChanged);
            }
            base.ClearItems();

            this.OnCollectionChanged(CollectionChangeAction.Refresh);
        }

        /// <summary>
        /// Items the changed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void ItemChanged(object sender, EventArgs e) {
            this.OnChanged();
        }

        /// <summary>
        /// Called when [changed].
        /// </summary>
        protected void OnChanged() {
            if (this.Changed != null) {
                this.Changed(this, new EventArgs());
            }
        }

        /// <summary>
        /// Called when [collection changed].
        /// </summary>
        /// <param name="action">The action.</param>
        protected void OnCollectionChanged(CollectionChangeAction action) {
            if (CollectionChanged != null) {
                CollectionChanged(this, new CollectionChangeEventArgs(action, this));
            }

            this.OnChanged();
        }
    }
}
